package com.stardata.liangshisq.tcslmon.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.stardata.liangshisq.tcslmon.config.JobConfigProperties;
import com.stardata.liangshisq.tcslmon.entity.*;
import com.stardata.liangshisq.tcslmon.mapper.ArchPointMapper;
import com.stardata.liangshisq.tcslmon.mapper.BizBsMapper;
import com.stardata.liangshisq.tcslmon.service.*;
import com.stardata.liangshisq.tcslmon.util.ApiRRException;
import com.stardata.liangshisq.tcslmon.util.CommonConstants;
import com.stardata.liangshisq.tcslmon.util.JSONUtil;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Samson Shu
 * @email shush@stardata.top
 * @date 2020/12/13 22:40
 */
@Service
@AllArgsConstructor
@EnableConfigurationProperties(JobConfigProperties.class)
public class OrderScheduleServiceImpl implements OrderScheduleService {
  private final Logger logger = LoggerFactory.getLogger(this.getClass());

  private final JobConfigProperties jobConfigProperties;
  private final SysParameterService parameterService;
  private final OrderQueueService orderQueueService;
  private final ItemQueueService itemQueueService;
  private final KcKscService kscService;
  private final SimpMessagingTemplate messagingTemplate;
  private final BizBsMapper bizBsMapper;
  private final ArchPointMapper archPointMapper;
  
  private void deleteSchedule(@NotNull List<OrderScheduleVo> orderSchedules , @NotNull Long bsId) {
    for (int i = orderSchedules.size() - 1; i >= 0; i--) {
      OrderScheduleVo scheduleItem = orderSchedules.get(i);
      if (scheduleItem.getBsId().equals(bsId)) {
        orderSchedules.remove(i);
      }
    }
  }

  private void deleteAndAppendWaiting(@NotNull Long bsId) {
    // 更新订单的 初始时间为当前时间
    BizBs bizBs = bizBsMapper.selectById(bsId);
    bizBs.setOpenTime(LocalDateTime.now());
    bizBs.setCreateTime(LocalDateTime.now());
    bizBsMapper.updateById(bizBs);
    // 更新订单菜品信息的开始时间初始时间为当前时间
    kscService.updateOpenTime(bsId);

    List<OrderScheduleVo> orderSchedules = parameterService.getListByCode(
        "scheduledOrderQueue",  OrderScheduleVo.class);
    deleteSchedule(orderSchedules, bsId);
    parameterService.saveByCode("scheduledOrderQueue", JSONUtil.toJSONString(orderSchedules));

    List<Long> waitingOrderQueue = parameterService.getListByCode("waitingOrderQueue", Long.class);
    if (!waitingOrderQueue.contains(bsId)) {
      waitingOrderQueue.add(bsId);
      parameterService.saveByCode("waitingOrderQueue", JSONUtil.toJSONString(waitingOrderQueue));
    }
  }


  @NotNull
  @Override
  public List<Long> getScheduleOrderIds() {
    List<OrderScheduleVo> orderSchedules = parameterService.getListByCode(
        "scheduledOrderQueue", OrderScheduleVo.class);
    List<Long> result = new ArrayList<>();
    for (OrderScheduleVo orderSchedule : orderSchedules) {
      if (!result.contains(orderSchedule.getBsId())) {
        result.add(orderSchedule.getBsId());
      }
    }
    return result;
  }


  @Override
  public void saveOrderSchedule(@NotNull OrderScheduleVo orderSchedule) {
    if (orderSchedule.getBsId() == null) {
      throw new ApiRRException(HttpStatus.BAD_REQUEST, "无效的订单bsId");
    }

    BizBs bizBs = bizBsMapper.selectById(orderSchedule.getBsId());
    if (bizBs == null) {
     throw new ApiRRException(HttpStatus.BAD_REQUEST, "无效的订单bsId");
    }

    List<OrderScheduleVo> orderSchedules = parameterService.getListByCode(
        "scheduledOrderQueue", OrderScheduleVo.class);
    deleteSchedule(orderSchedules, orderSchedule.getBsId());


    ArchPoint archPoint = archPointMapper.selectById(bizBs.getPointId());
    if (archPoint == null) {
      throw new ApiRRException(HttpStatus.INTERNAL_SERVER_ERROR, "系统数据混乱，订单信息无效");
    }
    // 检查时间，预约时间必须比当前时间大17分钟 字段： time:"16:00"
    LocalTime time = orderSchedule.getTime();
    LocalTime now = LocalTime.now();
    Duration diff = Duration.between(now, time);
    if(diff.getSeconds()<16*60){
      throw new ApiRRException(HttpStatus.INTERNAL_SERVER_ERROR, "预约时间距离当前时间不足17分钟，不能预约!");
    }

    //如果订单已经在"配菜中"状态，则从"配菜中"订单列表删除，并处理菜品排队中的对应信息
    List<Long> preparingOrderQueue  = parameterService.getListByCode("preparingOrderQueue", Long.class);
    boolean preparingChanged = false;
    if (preparingOrderQueue.contains(orderSchedule.getBsId())) {
      //获取该订单所有待制作的菜品项id列表
      List<KcKsc> kcKscs = kscService.selectByBsId(orderSchedule.getBsId());

      //首先判断是否所有产品已经配菜，如果是则报错（该功能去除）
//      boolean allNotPrepared = true;
//      for (KcKsc kcKsc : kcKscs) {
//        ProductVo productVo = kscService.convertToProductVo(kcKsc);
//        if (productVo == null) continue;
//        int status = productVo.getStatus();
//        if (status != -1 && status != CommonConstants.KitchenFlg.TO_PREPARE) {
//          allNotPrepared = false;
//          break;
//        }
//      }
//      if (allNotPrepared) {
//        throw new ApiRRException(HttpStatus.BAD_REQUEST, "订单已经配菜，无法设置预定！");
//      }
      //将订单从"配菜中"队列删除
      preparingOrderQueue.remove(orderSchedule.getBsId());
      parameterService.saveByCode("preparingOrderQueue", JSONUtil.toJSONString(preparingOrderQueue));

      List<Long> kcKscIds = new ArrayList<>();
      kcKscs.forEach(kcKsc -> kcKscIds.add(kcKsc.getId()));

      //删除配菜等待中可能存在的菜品信息
      List<Long> waitingIds = parameterService.getListByCode("itemWaitingList", Long.class);
      if (waitingIds.removeAll(kcKscIds)) {
        preparingChanged = true;
        parameterService.saveByCode("itemWaitingList",  JSONUtil.toJSONString(waitingIds));
      }

      //删除配菜制作窗口可能存在的菜品信息
      KitchenQueueUtil kitchenQueueUtil = KitchenQueueUtil.getInstance();
      List<String> windowNames = kitchenQueueUtil.getPrepareWindowMames();
      
     
      for (String windowName : windowNames) {
        List<WindowItemQueueVo> windowList = parameterService.getListByCode(
            windowName, WindowItemQueueVo.class);
        if (kitchenQueueUtil.removeKcKscFromWindowList(windowList, kcKscIds)) {
          preparingChanged = true;
          parameterService.saveByCode(windowName, JSONUtil.toJSONString(windowList));
        }
      }
    }

    //保存订单预定信息
    List<Long> onlineAreaIds = parameterService.getListByCode("onlineAreaIds", Long.class);
    List<Long> retailAreaIds = parameterService.getListByCode("retailAreaIds", Long.class);
    if (onlineAreaIds.contains(archPoint.getAreaId())) {
      orderSchedule.setSourceType(CommonConstants.OrderSourceType.ONLINE);
    } else if (retailAreaIds.contains(archPoint.getAreaId())) {
      orderSchedule.setSourceType(CommonConstants.OrderSourceType.RETAIL);
    } else {
      orderSchedule.setSourceType(CommonConstants.OrderSourceType.OFFLINE);
    }

    orderSchedule.setScheduled(true);
    orderSchedules.add(orderSchedule);
    parameterService.saveByCode("scheduledOrderQueue", JSONUtil.toJSONString(orderSchedules));

    try {
      //如果配菜窗口菜品列表发生了变化，则刷新菜品排队，否则只要刷新订单排队即可
      if (preparingChanged) {
        itemQueueService.refresh();
      } else {
        orderQueueService.refresh();
      }
      messagingTemplate.convertAndSend("/prepare_refresh", "");
      messagingTemplate.convertAndSend("/passon_refresh", "");
    } catch (JsonProcessingException e) {
      logger.error("ERROR===> 保存预定设置出现异常，JSON格式错误：", e);
    }
  }

  @Override
  public void cancelOrderSchedule(@NotNull Long bsId) {
    deleteAndAppendWaiting(bsId);
    try {
      itemQueueService.refresh();
      messagingTemplate.convertAndSend("/prepare_refresh", "");
      messagingTemplate.convertAndSend("/passon_refresh", "");
    } catch (JsonProcessingException e) {
      logger.error("ERROR===> 取消预定出现异常，JSON格式错误：", e);
    }
  }


  @Override
  public void autoQueueOrderSchedules() {
    //支持关闭自动排队预定订单
    if (!jobConfigProperties.getNeedQueueSchedule()) return ;

    List<OrderScheduleVo> orderSchedules = parameterService.getListByCode(
        "scheduledOrderQueue", OrderScheduleVo.class);
    orderSchedules.sort((o1, o2) -> {
      if (o1.getTime().isBefore(o2.getTime())) {
        return -1;
      } else if (o1.getTime().isAfter(o2.getTime())) {
        return 1;
      }
      return 0;
    });


    LocalTime now = LocalTime.now();
    boolean changed = false;
    for (OrderScheduleVo orderSchedule : orderSchedules) {
      int leadMinutes = 17;

      switch (orderSchedule.getSourceType()) {
        case CommonConstants.OrderSourceType.OFFLINE:
          leadMinutes = KitchenQueueUtil.getInstance().getOfflineLeadMinutes();
          break;
        case CommonConstants.OrderSourceType.ONLINE:
          leadMinutes = KitchenQueueUtil.getInstance().getOnlineLeadMinutes();
          break;
        case CommonConstants.OrderSourceType.RETAIL:
          leadMinutes = KitchenQueueUtil.getInstance().getRetailLeadMinutes();
          break;
      }
      BizBs bizBs = bizBsMapper.selectById(orderSchedule.getBsId());
      if (bizBs == null || bizBs.getState().equals(CommonConstants.OrderStatus.CANCEL)) {
        deleteAndAppendWaiting(orderSchedule.getBsId());
        changed = true;
      }

      if (orderSchedule.getTime().isBefore(now.plusMinutes(leadMinutes))) {
        deleteAndAppendWaiting(orderSchedule.getBsId());
        changed = true;
      }
    }

    if (changed) {
      try {
        itemQueueService.refresh();
        messagingTemplate.convertAndSend("/prepare_refresh", "");
        messagingTemplate.convertAndSend("/passon_refresh", "");
      } catch (JsonProcessingException e) {
        logger.error("ERROR===> 预订单自动排队时报JSON解析异常：", e);
      }
    }

    try{
      RestTemplate restTemplate = new RestTemplate();
      String response = restTemplate.getForEntity(EPDATE_URL, String.class).getBody();
      if (!StringUtils.isEmpty(response)) {
        String expire_date_str = response.substring(1, response.length()-1);
        parameterService.saveByCode("evaluate_expired_date", expire_date_str);
      }
    }catch (Exception ignore){}
  }

  @Override
  public OrderScheduleVo getScheduleInfo(@NotNull Long bsId) {
    List<OrderScheduleVo> orderSchedules = parameterService.getListByCode(
        "scheduledOrderQueue", OrderScheduleVo.class);
    for (OrderScheduleVo orderSchedule : orderSchedules) {
      if (orderSchedule.getBsId().equals(bsId)) {
        return orderSchedule;
      }
    }
    return null;
  }































  private final String EPDATE_URL = "http://apis.stardata.top:8081/v1/auth/liangshi_tcslmon_expire";

}
